package com.qianniu.napi.common.shiro;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.qianniu.napi.common.ShiroRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.util.Base64Utils;

import javax.servlet.Filter;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Created by chenxuebin on 2017/3/6.
 */
@Configuration
public class ShiroConfiguration {

    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean(name = "hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("MD5");
        credentialsMatcher.setHashIterations(3);
        credentialsMatcher.setStoredCredentialsHexEncoded(true);
        return credentialsMatcher;
    }


    @Bean(name = "shiroRealm")
    @DependsOn("lifecycleBeanPostProcessor")
    public ShiroRealm shiroRealm() {
        ShiroRealm realm = new ShiroRealm();
        realm.setCredentialsMatcher(hashedCredentialsMatcher());
        return realm;
    }

    @Bean(name = "ehCacheManager")
    @DependsOn("lifecycleBeanPostProcessor")
    public EhCacheManager ehCacheManager(){
        EhCacheManager cacheManager = new EhCacheManager();
        cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
        return cacheManager;
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm());
        securityManager.setCacheManager(ehCacheManager());

        // 配置 rememberMeCookie
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    //创建DefaultWebSessionManager类，并DI注入到IOC容器中
//    @Bean
//    public DefaultWebSessionManager mySessionManager(){
//        DefaultWebSessionManager defaultSessionManager = new DefaultWebSessionManager();
//        //将sessionIdUrlRewritingEnabled属性设置成false
//        defaultSessionManager.setSessionIdUrlRewritingEnabled(false);
//        return defaultSessionManager;
//    }

    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager  securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

//        Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
//        LogoutFilter logoutFilter = new LogoutFilter();
//        filters.put("logout", logoutFilter);
//        logoutFilter.setRedirectUrl("/login");

//        TokenFilter tokenFilter = new TokenFilter();
//        filters.put("token", tokenFilter);

        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/user/**", "authc,roles[user]");//authc 需要角色校验
        filterChainDefinitionMap.put("/shop/**", "authc,roles[shop]");//perms[内容]，perms["sourceC"] 表示需要内容所示的权限才能访问该路径-->
        filterChainDefinitionMap.put("/admin/**", "authc,roles[admin]");//roles[内容] 表示需要内容所示的角色才能访问该路径
        filterChainDefinitionMap.put("/stock/**", "authc,roles[admin]");// authc表示需要认证，没有进行身份认证是不能进行访问的
        filterChainDefinitionMap.put("/wx/**", "anon");//表示匿名访问，不需要认证以及授权
        filterChainDefinitionMap.put("/validcode", "anon");//表示匿名访问，不需要认证以及授权
        filterChainDefinitionMap.put("/dologin", "anon");//表示匿名访问，不需要认证以及授权
        filterChainDefinitionMap.put("/ajaxLogin", "anon");//表示匿名访问，不需要认证以及授权
        filterChainDefinitionMap.put("/css/**", "anon");//表示匿名访问，不需要认证以及授权
        filterChainDefinitionMap.put("/js/**", "anon");//表示匿名访问，不需要认证以及授权
        filterChainDefinitionMap.put("/fonts/**", "anon");//表示匿名访问，不需要认证以及授权
        filterChainDefinitionMap.put("/img/*", "anon");//表示匿名访问，不需要认证以及授权
        filterChainDefinitionMap.put("/test/**", "anon");//表示匿名访问，不需要认证以及授权
        filterChainDefinitionMap.put("/favicon.ico", "anon");//表示匿名访问，不需要认证以及授权
        filterChainDefinitionMap.put("/auth", "anon");//表示匿名访问，不需要认证以及授权
        filterChainDefinitionMap.put("/MP_verify_MUyEIyquOkU95eZP.txt", "anon");//表示匿名访问，不需要认证以及授权
        filterChainDefinitionMap.put("/**", "RemoveUrlJsessionId");
        filterChainDefinitionMap.put("/**", "authc");

        Map<String, Filter> map = new LinkedHashMap<String, Filter>();
        map.put("RemoveUrlJsessionId", new RemoveUrlJsessionIdFilter());
        map.put("authc", new MyFormAuthenticationFilter());
        shiroFilterFactoryBean.setFilters(map);

        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setSuccessUrl("/home");
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }

    /**
     * rememberMe cookie 效果是重开浏览器后无需重新登录
     *
     * @return SimpleCookie
     */
    private SimpleCookie rememberMeCookie() {
        // 设置 cookie 名称，对应 login.html 页面的 <input type="checkbox" name="rememberMe"/>
        SimpleCookie cookie = new SimpleCookie("rememberMe");
        // 设置 cookie 的过期时间，单位为秒，这里为一天
        cookie.setMaxAge(86400);
        return cookie;
    }

    /**
     * cookie管理对象
     *
     * @return CookieRememberMeManager
     */
    private CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        // rememberMe cookie 加密的密钥
        String encryptKey = "qianniu_shiro_key";
        byte[] encryptKeyBytes = encryptKey.getBytes(StandardCharsets.UTF_8);
        String rememberKey = Base64Utils.encodeToString(Arrays.copyOf(encryptKeyBytes, 16));
        cookieRememberMeManager.setCipherKey(Base64.decode(rememberKey));
        return cookieRememberMeManager;
    }


    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
        daap.setProxyTargetClass(true);
        return daap;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(securityManager);
        return aasa;
    }

    @Bean(name = "shiroDialect")
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

}
